#ifndef _SIP_SERVER_H_
#define _SIP_SERVER_H_

#include <thread>
#include <map>
#include "extension-base-class.h"
#include "eXosip2/eXosip.h"
#include "task-thread.h"
#include "hk-28181-simple-struct-define.h"

struct st_req_basicinfo
{
public:
    st_req_basicinfo(){
        memset(pc_from, 0x0, 64);
        memset(pc_to, 0x0, 64);
        memset(pc_device_channel_id, 0x0, 32);
        memset(pc_dev_ip, 0x0, 16);
        ui_dev_port = 0;
    }

    char pc_from[64];
    char pc_to[64];
    char pc_device_channel_id[32];
    char pc_dev_ip[16];
    unsigned int ui_dev_port;
};

struct st_dev_channel_id
{
public:
    st_dev_channel_id(){
        str_device_id.clear();
        str_channel_id.clear();
    }

    std::string str_device_id;
    std::string str_channel_id;
};

struct st_req_query_recordinfo
{
public:
    st_req_query_recordinfo(){
        memset(pc_start_time, 0x0, 64);
        memset(pc_end_time, 0x0, 64);
    }

    st_req_basicinfo st_req_url;
    char pc_start_time[64];
    char pc_end_time[64];
};
typedef st_req_query_recordinfo st_req_query_alarm;


struct st_req_control_ptz
{
public:
    st_req_control_ptz(){
        i_cmd = 0;
    }

    st_req_basicinfo st_req_url;
    int i_cmd;
};
typedef st_req_control_ptz st_req_control_record;
typedef st_req_control_ptz st_req_control_guard;

struct st_req_control_ptz_preset
{
public:
    st_req_control_ptz_preset(){
        i_cmd = 0;
        i_preset_no = 0;
    }

    st_req_basicinfo st_req_url;
    int i_cmd;//1 set, 2 goto, 3 del
    int i_preset_no;
};

struct st_subject_req
{
public:
    st_subject_req(){
        str_play.clear();
    }

    std::string str_play;
};

struct st_invite_play_realtime
{
public:
    st_invite_play_realtime(){
        str_device_id.clear();
    }

    st_req_basicinfo st_req_url;
    std::string str_device_id;
};


struct st_invite_playback
{
public:
    st_invite_playback(){
        memset(pc_start_time, 0x0, 32);
        memset(pc_end_time, 0x0, 32);
    }

    st_req_basicinfo st_req_url;
    std::string str_device_id;
    char pc_start_time[32];
    char pc_end_time[32];
};


struct st_invite_playback_pause
{
public:
    st_invite_playback_pause(){
        str_call_id.clear();
    }

    st_req_basicinfo st_req_url;
    std::string str_call_id;
};

struct st_invite_playback_scale
{
public:
    st_invite_playback_scale(){
        str_call_id.clear();
    }

    st_req_basicinfo st_req_url;
    std::string str_call_id;
    float f_scale;
};

typedef st_invite_playback_pause st_invite_playback_teardown;


struct st_invite_bye
{
public:
    st_invite_bye(){
        i_cmd = 0;
        str_call_id.clear();
    }

    st_req_basicinfo st_req_url;
    int i_cmd;//1 realtime, 2 playback, 3 download
    std::string str_call_id;
};

class sip_server
{
public:
    sip_server();
    ~sip_server();

    enum {
        timer_check_device_online = 1,
        timer_debug = 2,

        timer_max = 3,
    };

    bool server_start_equipment();

    bool set_register_callback(on_device_register_cb p_cb_fun, void *p_user);
    bool set_device_info_callback(on_device_info_cb p_cb_fun, void *p_user);
    bool set_device_status_callback(on_device_status_cb p_cb_fun, void *p_user);
    bool set_catalog_callback(on_device_catalog_cb p_cb_fun, void *p_user);
    bool set_device_info_callback(on_device_info_cb p_cb_fun, void *p_user);
    bool set_device_status_callback(on_device_status_cb p_cb_fun, void *p_user);
    bool set_invite_callback(on_device_channel_invite_cb p_cb_fun, void *p_user);
    bool set_recordinfo_callback(on_device_recordinfo_cb p_cb_fun, void *p_user);
    bool set_presetlists_callback(on_device_presetlist_cb p_cb_fun, void *p_user);

    unsigned long long get_sn();

    void send_unauthorized_response(eXosip_t *ctx, int tid, std::string &str_realm);

    bool add_register_dev(std::string &str_deviceid);
    bool del_register_dev(std::string &str_deviceid);
    bool check_register_status(std::string &str_deviceid);

    bool set_basic_info(std::string &str_deviceid, st_req_basicinfo &st_info);
    bool set_basic_info_by_catalog(std::string &str_device_id, Catalog_Response &st_catalog);
    bool get_basic_info(std::string &str_deviceid, st_req_basicinfo &st_info);

    bool set_catalog_info(std::string &str_device_id, Catalog_Response &st_catalog);

    bool set_invite_realtime_cmdplay(std::string &str_call_id, Cmd_Play &st_id);
    bool get_invite_realtime_cmdplay(std::string &str_call_id, Cmd_Play &st_id);
    bool del_invite_realtime_cmdplay(std::string &str_call_id);

    bool set_invite_playback_cmdplay(std::string &str_call_id, Cmd_Play &st_id);
    bool get_invite_playback_cmdplay(std::string &str_call_id, Cmd_Play &st_id);
    bool del_invite_playback_cmdplay(std::string &str_call_id);

    bool set_invite_download_cmdplay(std::string &str_call_id, Cmd_Play &st_id);
    bool get_invite_download_cmdplay(std::string &str_call_id, Cmd_Play &st_id);
    bool del_invite_download_cmdplay(std::string &str_call_id);

    /*********Query类**********/
    //设备目录信息查询请求
    bool post_request_catalog(std::string &str_device_id);
    //设备信息查询请求
    bool post_request_deviceinfo(std::string &str_device_id);
    //设备状态查询请求
    bool post_request_devicestatus(std::string &str_device_id);
    //文件目录检索请求RecordInfo, start_time:"2025-07-18T09:00:00", end_time:"2025-07-18T15:00:00"
    bool post_request_recordinfo(std::string &str_device_id, std::string &str_start_time, std::string &str_end_time);
    //报警查询Alarm(28181-2016 P61)
    bool post_request_alarm(std::string &str_device_id, std::string &str_start_time, std::string &str_end_time);
    //设备配置查询(28181-2016 P62-实测无响应)
    bool post_request_configdownload(std::string &str_device_id);
    //设备预置位查询
    bool post_request_presetlist(std::string &str_device_id);

    /*********Subscribe类**********/
    bool post_subscribe_catalog(std::string &str_device_id);

    /*********Control类**********/
    //云台控制上下左右
    bool post_control_ptz(std::string &str_device_id, int i_ptz_cmd);
    //预置位
    bool post_control_ptz_preset(std::string &str_device_id, int i_cmd, int i_preset);
    //变倍, 0停，1近，2远
    bool post_control_visual_zoom(std::string &str_device_id, std::string &str_device_channel_id, int i_cmd);
    //聚焦, 0停，1聚焦近，2聚焦远，3光圈缩小，4光圈放大，
    bool post_control_visual_focus_iris(std::string &str_device_id, std::string &str_device_channel_id, int i_cmd);
    //远程启动
    bool post_control_teleboot(std::string &str_device_id);
    //录像控制(1 record, 2 stop_record)
    bool post_control_record(std::string &str_device_id, int i_cmd);
    //报警布防、撤防(1 SetGuard, 2 ResetGuard)
    bool post_control_guard(std::string &str_device_id, int i_cmd);
    //报警复位(AlarmCmd--未做)
    bool post_control_alarm(std::string &str_device_id, int i_cmd);

    //强制I帧

    //看守位控制命令

    /*********INVITE类**********/
    //实时播放Play
    bool post_invite_play(std::string &str_dev_id, std::string &str_device_channel_id);
    bool post_invite_bye(std::string &str_dev_id, std::string &str_device_channel_id, std::string &str_call_id);
    //回放, start_time:1752806100, end_time:1752806700
    bool post_invite_playback(std::string &str_dev_id, std::string &str_device_channel_id, std::string &str_start_time, std::string &str_end_time);
    bool post_invite_playback_pause(std::string &str_dev_id, std::string &str_device_channel_id, std::string &str_call_id);
    bool post_invite_playback_continue(std::string &str_dev_id, std::string &str_device_channel_id, std::string &str_call_id);
    bool post_invite_playback_scale(std::string &str_dev_id, std::string &str_device_channel_id, std::string &str_call_id, float f_scale);
    bool post_invite_playback_teardown(std::string &str_dev_id, std::string &str_device_channel_id, std::string &str_call_id);
    bool post_invite_playback_bye(std::string &str_dev_id, std::string &str_device_channel_id, std::string &str_call_id);
    //下载(要实现下载功能，ZLMediaKit的配置需要如下修改：rtp_proxy.dumpDir需要指定目录与record.filePath保持一致，record.appName修改为rtp)
    bool post_invite_download(std::string &str_dev_id, std::string &str_device_channel_id, std::string &str_start_time, std::string &str_end_time);
    bool post_invite_download_bye(std::string &str_dev_id, std::string &str_device_channel_id, std::string &str_call_id);

public:
    static void to_request_catalog(void *p_arg_first, void *p_arg_second);
    static void to_request_device_info(void *p_arg_first, void *p_arg_second);
    static void to_request_device_status(void *p_arg_first, void *p_arg_second);
    static void to_request_preset_list(void *p_arg_first, void *p_arg_second);
    static void to_request_device_recordinfo(void *p_arg_first, void *p_arg_second);
    static void to_request_device_alarm(void *p_arg_first, void *p_arg_second);
    static void to_request_configdownload(void *p_arg_first, void *p_arg_second);

    static void to_subscribe_catalog(void *p_arg_first, void *p_arg_second);

    static void to_control_ptz(void *p_arg_first, void *p_arg_second);
    static void to_control_ptz_preset(void *p_arg_first, void *p_arg_second);
    static void to_control_visual_zoom(void *p_arg_first, void *p_arg_second);
    static void to_control_visual_focus_iris(void *p_arg_first, void *p_arg_second);
    static void to_control_teleboot(void *p_arg_first, void *p_arg_second);
    static void to_control_record(void *p_arg_first, void *p_arg_second);
    static void to_control_guard(void *p_arg_first, void *p_arg_second);

    static void to_invite_play(void *p_arg_first, void *p_arg_second);
    static void to_invite_playback(void *p_arg_first, void *p_arg_second);
    static void to_invite_playback_pause(void *p_arg_first, void *p_arg_second);
    static void to_invite_playback_continue(void *p_arg_first, void *p_arg_second);
    static void to_invite_playback_scale(void *p_arg_first, void *p_arg_second);
    static void to_invite_playback_teardown(void *p_arg_first, void *p_arg_second);
    static void to_invite_download(void *p_arg_first, void *p_arg_second);
    static void to_invite_bye(void *p_arg_first, void *p_arg_second);

    static void timer_check_device_online_func(unsigned int ui_timer, void *arg);

    //以下接口仅测试使用
#ifdef DEBUG_TEST
    static void timer_send_playback_control_func(unsigned int ui_timer, void *arg);
#endif

private:
    void hk_eXosip_processEvent_subordinate_equipment();
    bool get_dev_ip_from_msg(osip_message_t *pt_message, std::string &str_ip, unsigned int &us_port);


private:
    struct eXosip_t *mp_ectx_equipment = nullptr;

    bool mb_thread_fini = false;
    std::thread *mpt_event_thread = nullptr;

    std::mutex mo_register_dev_mutex;
    std::map<std::string, time_t> mstr_register_dev_map;
    std::map<std::string, st_req_basicinfo> mst_dev_basic_info;//string: dev_id-channel_id

    std::mutex mo_task_thread_mutex;
    HHAThread::TaskThread *mp_task_thread = nullptr;

    std::mutex mo_sn_mutex;
    unsigned long long mull_sn = 100000000;

    std::mutex mo_device_catalog_mutex;
    std::map<std::string, Catalog_Response> mst_dev_catalog_map;

    std::mutex mo_invite_mutex;
    unsigned int mui_invite_y = 100000001;
    std::map<std::string, st_dev_channel_id> mst_callid_to_dev_channel_id;//call-id, device id and channel id
    std::map<std::string, Cmd_Play> mst_cmd_play_realtime_map; //call-id, Cmd_Play
    std::map<std::string, Cmd_Play> mst_cmd_play_back_map;
    std::map<std::string, Cmd_Play> mst_cmd_play_download_map;

    std::mutex mo_register_callback_mutex;
    on_device_register_cb  mp_register_cb_func = nullptr;
    void *mp_register_cb_user = nullptr;

    std::mutex mo_device_info_callback_mutex;
    on_device_info_cb mp_device_info_cb_func = nullptr;
    void *mp_device_info_cb_user = nullptr;

    std::mutex mo_device_status_callback_mutex;
    on_device_status_cb mp_device_status_cb_func = nullptr;
    void *mp_device_status_cb_user = nullptr;

    std::mutex mo_catalog_callback_mutex;
    on_device_catalog_cb mp_catalog_cb_func = nullptr;
    void *mp_catalog_cb_user = nullptr;

    std::mutex mo_invite_callback_mutex;
    on_device_channel_invite_cb mp_invite_cb_func = nullptr;
    void *mp_invite_cb_user = nullptr;

    std::mutex mo_record_info_callback_mutex;
    on_device_recordinfo_cb mp_record_info_cb_func = nullptr;
    void *mp_record_info_cb_user = nullptr;

    std::mutex mo_preset_list_callback_mutex;
    on_device_presetlist_cb mp_preset_list_cb_func = nullptr;
    void *mp_preset_list_cb_user = nullptr;
};

typedef singleton_locker_factory<sip_server> singleton_lock_sip_server_handler;

#endif
